// ========================================================================
// Copyright 2007 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at 
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//========================================================================

package dojox.cometd.demo;


import javax.servlet.ServletContext;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;

import org.mortbay.cometd.BayeuxService;
import org.mortbay.log.Log;

import db.derby.SingleTonDBWrapper;
import dojox.cometd.Bayeux;
import dojox.cometd.Client;
import dojox.cometd.Listener;
import dojox.cometd.Message;
import dojox.cometd.MessageListener;
import dojox.cometd.RemoveListener;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArraySet;
import java.sql.*;

public class BayeuxStartupListener implements ServletContextAttributeListener
{
    public void initialize(Bayeux bayeux)
    {
        synchronized(bayeux)
        {
            if (!bayeux.hasChannel("/service/srcar"))
            {
                //new EchoRPC(bayeux);
                //new Monitor(bayeux);
                new SRCarService(bayeux);
            }
        }
        
    }
    
    public void attributeAdded(ServletContextAttributeEvent scab)
    {
        if (scab.getName().equals(Bayeux.DOJOX_COMETD_BAYEUX))
        {
            Bayeux bayeux=(Bayeux)scab.getValue();
            initialize(bayeux);
        }
    }

    public void attributeRemoved(ServletContextAttributeEvent scab)
    {

    }

    public void attributeReplaced(ServletContextAttributeEvent scab)
    {

    }

    
    public static class EchoRPC extends BayeuxService
    {
        public EchoRPC(Bayeux bayeux)
        {
            super(bayeux,"echo");
            subscribe("/service/echo","doEcho");
        }
        
        public Object doEcho(Client client, Object data)
        {
	    Log.info("ECHO from "+client+" "+data);
	    return data;
        }
    }
    
    public static class Monitor extends BayeuxService
    {
        public Monitor(Bayeux bayeux)
        {
            super(bayeux,"monitor");
            subscribe("/meta/subscribe","monitorSubscribe");
            subscribe("/meta/unsubscribe","monitorUnsubscribe");
            subscribe("/meta/*","monitorMeta");
        }
        
        public void monitorSubscribe(Client client, Message message)
        {
            Log.info("Subscribe from "+client+" for "+message.get(Bayeux.SUBSCRIPTION_FIELD));
        }
        
        public void monitorUnsubscribe(Client client, Message message)
        {
            Log.info("Unsubscribe from "+client+" for "+message.get(Bayeux.SUBSCRIPTION_FIELD));
        }
        
        public void monitorMeta(Client client, Message message)
        {
            Log.debug(message.getChannel()+" from "+client);
        }
    }
    /**
     * Service reporting surrounded cars
     * @author xiaohong
     *
     */
    public static class SRCarService extends BayeuxService
    {
        //ConcurrentMap<String,Set<String>> _members = new ConcurrentHashMap<String,Set<String>>();
        SingleTonDBWrapper db=SingleTonDBWrapper.getInstance();//db
        public SRCarService(Bayeux bayeux)
        {
            super(bayeux,"srcar");      //Surrounded cars services
            subscribe("/service/srcar","trackLocation");
        }
        
        /**
         * 
         * @param len String length
         * @return random string
         */
        public static String getUniqueID(int len) {        	
        	String chars = "abcdefghijklmonpqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";        	
        	java.util.Random r = new java.util.Random();
        
        char[] buf = new char[len];        
        for (int i = 0; i < buf.length; i++) {        
          buf[i] = chars.charAt(r.nextInt(chars.length()));        
        }
        return new String(buf);       
      }
        /**
         * Track vehicle location
         * @param joiner
         * @param channel
         * @param data
         * @param id
         * mid  modelid used in singleTonDBWrapper.
         * @return
         */
        public Map<String,Object> trackLocation(Client joiner,String channel,Map<String,Object> data,String id)
        {
        	
         System.out.println(data);
        if (Boolean.TRUE.equals(data.get("report")))
            {
              String [] avs=((String)data.get("data")).split(";");
              String user=(String)data.get("user");
              String uid=(String)data.get("uid");
              if(uid==null)return data;
              String sr;
              float lat=0,lon=0,alt=0,vel=0,heading=0;
              String mid=null;
              for(int i=0;i<avs.length;i++){
            	  System.out.println(avs[i]);   	  
            	  if (avs[i] !=null){
            		  String[] av=avs[i].split("=");
            		  if(av.length>1){
            			  if("lat".equals(av[0])){
            				  lat=Float.parseFloat(av[1]);
            			  }else if("lon".equals(av[0])){
            				  lon=Float.parseFloat(av[1]);
            			  }else if("alt".equals(av[0])){
            				  alt=Float.parseFloat(av[1]);
            			  }else if("v".equals(av[0])){
            				  vel=Float.parseFloat(av[1]);
            			  }else if("mid".equals(av[0])){
            				  mid=av[1];
            			  }else if("heading".equals(av[0])){
            				  heading=Float.parseFloat(av[1]);
            			  }
            		  }
            	  }            	  
              }
              db.insertData(uid,
            		  user,
            		 lat,
            		 lon,
            		 alt,
            		 vel,
            		 mid,
            		 heading
             );
              sr=this.getSurrounded(uid, lat, lon);
              if (!sr.isEmpty()){
            		data.put("surrounded", sr);
            	}
             // data.put("surrounded", sr);
              //  System.out.println(user+":"+avs[0].split("=")[1]+":"+avs[1].split("=")[1]+
               // ":"+avs[2].split("=")[1]);
            }else if (Boolean.TRUE.equals(data.get("join"))){
            	//asign a unique id to a client
            	String uid=SRCarService.getUniqueID(10);
            	data.put("uid", uid);
            }
            return data;
        }
        /**
         * Surrounded cars(id,lat,lon,alt,vel,mid)of me
         * @param me
         * @param lat latitude
         * @param lon longitude
         * @return car list in format id:x:y:v:mid<BR>...
         */
        public String getSurrounded(String me,float lat,float lon){
          	String query;
          	query="select username,fid,lat,lon,alt,vel,mid,heading ,lat-"+lat+" latdiff, lon-"+lon+" londiff from pos_vel where id in ("+
          		"select max(id) from pos_vel where fid <> '"+me+"' group by fid) and" +
          		" abs(lat-"+lat+")<0.01 and abs(lon-"+lon+")<0.01";
          	String result="";
          	ResultSet rs= db.ExeQuery(query);
          	try{
            while(rs.next()){
            	//@attention: update neighbour.js accordingly
            	result+=rs.getString("USERNAME")+":"+rs.getString("FID")+":"+rs.getFloat("LAT")+":"+rs.getFloat("LON")+":"
            	+rs.getFloat("ALT")+":"
            	//2
            	+Math.round(rs.getFloat("VEL")*100)/100+":"
            	+rs.getFloat("HEADING")+":"
            	+rs.getString("MID")+":"
            	+rs.getFloat("LATDIFF")+":"
            	+rs.getFloat("LONDIFF")+"<BR>";
            }
          	}catch(SQLException e){e.printStackTrace();}
            return result;
        }
    }          	

}
	